#include "GfxEffects.h"
#include "Gfx.h"
#include "Timer.h"

void flash (int r, int g, int b, Uint32 msclear, Uint32 msflash, int repeat) {
	Uint32 color;
	int k;
	Gfx *gfx = Gfx::instance();
	SDL_Surface *screen = gfx->getScreen();

	color = SDL_MapRGB(screen->format, r, g, b);
	
	for ( k = 0; k < repeat; k++ )
	{
		gfx->saveScreen();
		SDL_FillRect(screen, NULL, color);
		SDL_Delay(msflash);
		
		gfx->restoreScreen();
		SDL_Delay(msclear);
	}	
}

void flash (int r, int g, int b, Uint32 ms, int repeat) {
	flash (r,g,b,ms,ms,repeat);
}

void flash (int r, int g, int b, Uint32 msflash) {
	flash (r,g,b,0,msflash,0);
}

void faderZoneIn (void) {
  SDL_Surface *screen = Gfx::instance()->getScreen();

  for (int k = 32; k >= 0; k--) {
    Timer::tick();

    SDL_Rect rect = {
      k * 32,
      k * 24,
      1024 - 2 * k *32,
      768  - 2 * k *24
    };
    SDL_FillRect    (screen, &rect, 0);
    SDL_UpdateRects (screen, 1, &rect);

    Timer::tickAndWait(10);
  }
}

void faderZoneIn (SDL_Surface *surface) {
  SDL_Surface *screen = Gfx::instance()->getScreen();

  for (int k = 16; k >= 0; k--) {
    Timer::tick();

    SDL_Rect rect = {
      k * 32,
      k * 24,
      1024 - 2 * k *32,
      768  - 2 * k *24
    };
    SDL_BlitSurface (surface, &rect, screen, &rect);
    SDL_UpdateRects (screen, 1, &rect);

    Timer::tickAndWait(20);
  }
}

void faderZoneOut (void) {
  SDL_Surface *screen = Gfx::instance()->getScreen();
  SDL_Surface *buffer = Gfx::instance()->getBuffer();

  // Copy screen contents
  SDL_Rect rect = { 0, 0, 1024, 768 };
  SDL_BlitSurface (screen, &rect, buffer, &rect);

  for (int k = 0; k <= 16; k++) {
    Timer::tick();

    SDL_FillRect(screen, NULL, 0);
    SDL_Rect rect = {
      k * 32,
      k * 24,
      1024 - 2 * k *32,
      768  - 2 * k *24
    };
    SDL_BlitSurface (buffer, &rect, screen, &rect);
    SDL_UpdateRect  (screen, 0, 0, 1024, 768);
    
    Timer::tickAndWait(20);
  }
}

// 313, 307, ((295))
#define CHESSBOARD_SEED (295)
void faderChessBoard () {
	// The current screen breaks in little rectangular
	// areas which leave the screen following a random
	// direction (fixed rectangle size)
	const int w  = 32;
	const int h  = 32;
	const int nw = 1024 / w;
	const int nh = 768 / h;
	
	SDL_Surface *screen = Gfx::instance()->getScreen();

	int nZones = nw*nh;

  SDL_Rect rect;
  int selector;

  // Find an increment number for "selector" which is not a divisor of nw*nh
  for (int k = 0, selector = 0; k < nZones; k++,
        selector = (selector+CHESSBOARD_SEED) % nZones) {
    Timer::tick();

    rect.x = (selector % nw) * w;
    rect.y = (selector / nw) * h;
    rect.w = w;
    rect.h = h;

    SDL_FillRect (screen, &rect, 0);
    SDL_UpdateRects (screen, 1, &rect);

    Timer::tickAndWait(2);
  }
}

void faderChessBoard (SDL_Surface *surface) {
	// The current screen breaks in little rectangular
	// areas which leave the screen following a random
	// direction (fixed rectangle size)
	const int w  = 32;
	const int h  = 32;
	const int nw = 1024 / w;
	const int nh = 768 / h;
	
	SDL_Surface *screen = Gfx::instance()->getScreen();

	int nZones = nw*nh;

  // Find an increment number for "selector" which is not a divisor of nw*nh

  SDL_Rect rect;
  int selector;

  for (int k = 0, selector = 0; k < nZones; k++,
        selector = (selector+CHESSBOARD_SEED) % nZones) {
    Timer::tick();
  
    rect.x = (selector % nw) * w;
    rect.y = (selector / nw) * h;
    rect.w = w;
    rect.h = h;
   
    SDL_BlitSurface(surface, &rect, screen, &rect);
    SDL_UpdateRects (screen, 1, &rect);

    Timer::tickAndWait(2);
  }
}

void faderHBreak (void) {
	SDL_Surface *screen = Gfx::instance()->getScreen();
  SDL_Surface *buffer = Gfx::instance()->getBuffer();

  const int h = 16;
  const int N = 768 / h;
  const int hBand = 3*h;

  // Copy screen contents
  SDL_Rect rect = { 0, 0, 1024, 768 };
  SDL_BlitSurface (screen, &rect, buffer, &rect);

  SDL_Rect clearRect = { 0, 0, 1024, 768 };
  SDL_Rect area      = { 0, 0, 1024, h  };

  rect.h = h;

  for (int k = 1; k <= N; k++) {
    Timer::tick();

    int cursor = 768 - k * h;

    area.y = cursor;

    clearRect.y = cursor;
    clearRect.h = clearRect.y + hBand;

    for (int y = cursor; y < cursor+hBand; y+=10) {
      rect.y = y;
      SDL_FillRect (screen, &clearRect, 0);
      SDL_BlitSurface (buffer, &area, screen, &rect);
      SDL_UpdateRects (screen, 1, &clearRect);
    }
    Timer::tickAndWait(2);
  }

  // Clear the whole screen
  Gfx::instance()->clearScreen();
}

void faderHBreak (SDL_Surface *surface) {
	SDL_Surface *screen = Gfx::instance()->getScreen();
  SDL_Surface *buffer = Gfx::instance()->getBuffer();

  const int h = 16;
  const int N = 768 / h;
  const int hBand = 3*h;

  // Copy screen contents
  SDL_Rect rect = { 0, 0, 1024, 768 };
  SDL_BlitSurface (screen, &rect, buffer, &rect);

  SDL_Rect clearRect = { 0, 0, 1024, 768 };
  SDL_Rect area      = { 0, 0, 1024, h  };

  rect.h = h;

  for (int k = 1; k <= N; k++) {
    Timer::tick();

    int cursor = 768 - k * h;

    area.y = cursor;

    clearRect.y = cursor;
    clearRect.h = clearRect.y + hBand;

    for (int y = cursor; y < cursor+hBand; y+=10) {
      rect.y = y;
      //SDL_FillRect (screen, &clearRect, 0);
      SDL_BlitSurface (surface, &clearRect, screen, &clearRect);
      SDL_BlitSurface (buffer, &area, screen, &rect);
      SDL_UpdateRects (screen, 1, &clearRect);
    }
    Timer::tickAndWait(20);
  }

  // Blit the whole surface
  SDL_BlitSurface (surface, NULL, screen, NULL);
  SDL_UpdateRect  (screen, 0, 0, 1024, 768);
}

